package beerAgent;

import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

public class BeerGame implements BeerModel {
	private List<FallingObject> objects = new ArrayList<FallingObject>();

	private int nofObects;
	private int mapHeight = 15;
	private int mapWidth = 30;
	private final static int playerLength = 5;
	private static final double captureRate = 0.8;
	private int maxObjectSize, minObjectSize;
	// private int playerColumn=10;
	private FallingObject fallingObject;
	private FallingObject player;

	private BeerPanel panel;
	private int count = 0;
	private boolean draw = true;
	private boolean horizontalSpeed;

	private boolean dynamicMap = false;

	// private Object modi;

	public BeerGame(int nofObects, int minLength, int maxLength,
			boolean horizontalSpeed, int width, int height) {
		super();
		this.horizontalSpeed = horizontalSpeed;
		this.maxObjectSize = maxLength;
		this.minObjectSize = minLength;
		this.nofObects = nofObects;
		this.mapWidth = width; 
		this.mapHeight = height; 

		panel = new BeerPanel(this);
		generateObjects();
		player = FallingObject.getPlayer(playerLength, mapWidth, mapHeight);
	}
	
//	public void setMapDimentions(int width, int height){
//	}

	private void generateObjects() {
		objects = new ArrayList<FallingObject>();
		for (int i = 0; i < nofObects; i++) {
			objects.add(new FallingObject(maxObjectSize, minObjectSize,
					mapWidth, horizontalSpeed));
		}
	}

	public Scenario move(int move) {
		fallingObject = nextObject(count);

		player.moveHorizontal(move);
		Scenario returnValue = dropFallingObject();

		if (draw) {
			panel.drawGame();
		}
		return returnValue;
	}

	private FallingObject nextObject(int count) {
		if (dynamicMap) {
			if (fallingObject == null
					|| fallingObject.getRow() == player.getRow() - 1) {
				return new FallingObject(maxObjectSize, minObjectSize,
						mapWidth, horizontalSpeed);
			} else {
				return fallingObject;
			}
		} else {
			return objects.get(count);
		}
	}

	private Scenario dropFallingObject() {
		fallingObject.drop();

		int objectLength = fallingObject.getLength();
		int objectRow = fallingObject.getRow();

		if (objectRow == mapHeight - 1)
			fallingObject.reset();
		if (objectRow == mapHeight - 2) {
			count += 1;

			if (objectLength >= playerLength && sensorsTrue() == playerLength)
				return Scenario.CATCH_LARGE;
			else if (sensorsTrue() > objectLength * getCaptureRate())
				return Scenario.CATCH_SMALL;
			else if ((sensorsTrue() == 0) && (objectLength >= playerLength))
				return Scenario.MISS_LARGE;
			else if ((sensorsTrue() < playerLength)
					&& (objectLength >= playerLength))
				return Scenario.HIT_BY_LARGE;
			else if (sensorsTrue() <= objectLength * getCaptureRate()
					&& sensorsTrue() > 0)
				return Scenario.HIT_BY_SMALL;
			else
				return Scenario.MISS_SMALL;

		}

		return Scenario.NEUTRAL;
	}

	public boolean[] getSensors() {
		boolean[] sensors = new boolean[playerLength];
		if (fallingObject == null || fallingObject.getRow() < 0) {
			return sensors;
		}
		int sensor = 0;
		int modi;

		for (int i = player.getColumn(); i < player.getColumn()
				+ player.getLength(); i++) {
			modi = modulus(i, mapWidth);
			if (fallingObject.atColumn(modi)) {
				sensors[sensor] = true;
			}
			sensor++;
		}
		return sensors;
	}

	private int sensorsTrue() {
		int sum = 0;
		boolean[] sensors = getSensors();
		for (boolean sensor : sensors) {
			if (sensor)
				sum += 1;
		}
		return sum;
	}

	private static int modulus(int a, int b) {
		while (a < 0)
			a += b;
		return a % b;
	}

	private double getCaptureRate() {
		return captureRate;
	}

	public boolean isFinished() {
		return count == objects.size();
	}

	public JPanel getGamePanel() {
		if (panel == null) {
			return new JPanel();
		}
		return panel;
	}

	public void setDraw(boolean draw) {
		this.draw = draw;
		if (draw) {
			panel = new BeerPanel(this);
		}
	}

	public int getMapHeight() {
		return mapHeight;
	}

	public int getMapWidth() {
		return mapWidth;
	}

	public int getMapDim() {
		return mapWidth * mapHeight;
	}

	public void reset() {
		if (fallingObject != null)
			fallingObject.setRow(-2);
		// playerColumn = 10;
		count = 0;
		for (FallingObject object : objects) {
			object.reset();
		}
		player.reset();
	}

	public BeerGame copy() {
		BeerGame copy = new BeerGame(nofObects, minObjectSize, maxObjectSize,
				this.horizontalSpeed, this.mapWidth, this.mapHeight);
		copy.objects = new ArrayList<FallingObject>();
		for (int i = 0; i < this.objects.size(); i++) {
			copy.objects.add(this.objects.get(i).copy());
		}

		copy.reset();
		return copy;
	}

	@Override
	public String toString() {
		String map = "";
		for (int i = 0; i < mapHeight; i++) {
			for (int j = 0; j < mapWidth; j++) {
				map += getCell(i, j);
			}
			map += "\n";
		}
		return map;
	}

	public char getCell(int row, int col) {
		// int objectRow = fallingObject.getRow();

		if (player.atPosition(row, col)) {
			return 'p';
		} else if (fallingObject.atPosition(row, col)) {
			return 'o';
		}
		return '.';
	}

	public void setDynamicMap(boolean value){
		this.dynamicMap = value; 
	}
	
}
